package com.prd.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.prd.dto.AttendanceOtDTO;
import com.prd.dto.AttendanceOutsideDTO;
import com.prd.model.AttendanceOtDO;
import com.prd.mapper.AttendanceOtMapper;
import com.prd.model.AttendanceOutsideDO;
import com.prd.service.AttendanceOtService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.prd.util.JsonData;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 加班管理表数据 服务实现类
 * </p>
 *
 * @author lizhaoyi
 * @since 2023-10-19
 */
@Service
@Slf4j
public class AttendanceOtServiceImpl extends ServiceImpl<AttendanceOtMapper, AttendanceOtDO> implements AttendanceOtService {

    @Autowired
    private AttendanceOtMapper attendanceOtMapper;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Qualifier("processEngine")
    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private HistoryService historyService;


    /**
     * 申请加班并启动工作流
     * @param attendanceOtDTO
     * @return
     */
    @Override
    public JsonData askForOt(AttendanceOtDTO attendanceOtDTO) {
        //启动工作流
        String processId = startProcess(attendanceOtDTO);
        attendanceOtDTO.setProcessId(processId);
        attendanceOtDTO.setCreatedTime(LocalDateTime.now());
        AttendanceOtDO attendanceOtDO = new AttendanceOtDO();
        BeanUtils.copyProperties(attendanceOtDTO,attendanceOtDO);

        if (attendanceOtMapper.insert(attendanceOtDO) > 0) {
            return JsonData.buildSuccess();
        }

        return JsonData.buildError("申请加班数据异常");

    }

    /**
     * 分页查询加班申请记录
     * @param page
     * @param size
     * @param userId
     * @return
     */
    @Override
    public Map<String, Object> page(int page, int size, String userId) {

        Page<AttendanceOtDO> pageInfo = new Page<>(page, size);
        IPage<AttendanceOtDO> productDOIPage = attendanceOtMapper.selectPage(pageInfo, new LambdaQueryWrapper<AttendanceOtDO>()
                .eq(AttendanceOtDO::getApplicantId,userId)
                .eq(AttendanceOtDO::getIsDelete,0));

        Map<String, Object> pageMap = new HashMap<>(3);
        pageMap.put("total_record", productDOIPage.getTotal());
        pageMap.put("total_page", productDOIPage.getPages());
        pageMap.put("current_data", productDOIPage.getRecords().stream().map(obj -> do2Dto(obj)).collect(Collectors.toList()));

        return pageMap;
    }

    /**
     * 查看申请加班详情
     * @param id
     * @param userId
     * @return
     */
    @Override
    public JsonData getDetail(int id, String userId) {

        AttendanceOtDO attendanceOtDO = attendanceOtMapper.selectOne(new LambdaQueryWrapper<AttendanceOtDO>()
                .eq(AttendanceOtDO::getId,id)
                .eq(AttendanceOtDO::getApplicantId,userId));
        if (attendanceOtDO != null) {
            return JsonData.buildSuccess(attendanceOtDO);
        }
        return null;
    }

    /**
     * 查看工作流程图
     * @param resp
     * @param processId
     */
    @Override
    public void showProcessPic(HttpServletResponse resp, String processId) throws IOException {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        if (pi == null) {
            return;
        }
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(processId)
                .list();

        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        /**
         * 生成流程图
         */
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, false);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = resp.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 取消加班
     * @param attendanceOtDTO
     * @return
     */
    @Override
    public JsonData cancelOt(AttendanceOtDTO attendanceOtDTO) {

        //删除工作流
        deleteProcessInstanceById(attendanceOtDTO.getProcessId());

        AttendanceOtDO attendanceOtDO = dto2Do(attendanceOtDTO);

        int count = attendanceOtMapper.update(attendanceOtDO, new UpdateWrapper<AttendanceOtDO>().lambda()
                .set(AttendanceOtDO::getProcessId, null)
                .set(AttendanceOtDO::getIsDelete, 1));
        if (count > 0) {
            return JsonData.buildSuccess();
        }

        return JsonData.buildError("取消加班异常");
    }


    private String startProcess(AttendanceOtDTO attendanceOtDTO) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("zuzhangTask", attendanceOtDTO.getApproveName());
        // 开启流程的key，就是流程定义文件里 process 标签的id
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ask_for_ot", map);
        // 设置一些参数
        runtimeService.setVariable(processInstance.getId(), "name", attendanceOtDTO.getApplicantName());
        runtimeService.setVariable(processInstance.getId(), "reason", attendanceOtDTO.getTitle());
        runtimeService.setVariable(processInstance.getId(), "date", attendanceOtDTO.getOtDate());
        log.info("创建外勤流程 processId：{}", processInstance.getId());
        return processInstance.getId();
    }

    public void deleteProcessInstanceById(String processInstanceId) {
        long count = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).count();
        if (count > 0) {
            runtimeService.deleteProcessInstance(processInstanceId, "删除流程实例");
        } else {
            //删除历史数据
//            historyService.deleteHistoricProcessInstance(processInstanceId);
        }
    }

    private AttendanceOtDTO do2Dto(AttendanceOtDO attendanceOtDO) {
        AttendanceOtDTO attendanceOtDTO = new AttendanceOtDTO();
        BeanUtils.copyProperties(attendanceOtDO, attendanceOtDTO);
        return attendanceOtDTO;
    }

    private AttendanceOtDO dto2Do(AttendanceOtDTO attendanceOtDTO) {
        AttendanceOtDO attendanceOtDO = new AttendanceOtDO();
        BeanUtils.copyProperties(attendanceOtDTO, attendanceOtDO);
        return attendanceOtDO;
    }
}
